﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ole = AnalysisSystem.OleDbMethod;

namespace AnalysisSystem
{
    class SingleWellSummary
    {
        public static DataTable singleWellSumTable = new DataTable();
        //分类统计中用到的数据
        public static double[] allSum = new double[3];  //顺序为油、水、气
        public static List<double> singleWellData = new List<double>();
        public static void SingleWellSum()
        {            
            InitialTable();
            int startRow = 0, endRow = -1;
            for (int i = 0; i < singleWellSumTable.Rows.Count; i++)
            {
                startRow = endRow + 1;
                string wellNumString = singleWellSumTable.Rows[i][1].ToString();
                int produceDay = 0;
                //顺序为油，水，气
                int[] productionDay = new int[3];
                double[] sumData = new double[3];
                double[] maxData = new double[3];
                double[] averageData = new double[3];
                double[] dailyData = new double[3];
                //计算油，水，气累计值、最大值以及实际生产天数
                for (int j = startRow; NumCheck(wellNumString, j); j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        dailyData[k] = valueProcess(j, 6 + k);
                        sumData[k] += dailyData[k];
                        maxData[k] = doubleMax(maxData[k], dailyData[k]);
                        if (!dailyData[k].Equals(0)) productionDay[k]++;
                    }
                    if (IsProduce(dailyData))
                        produceDay++;
                    endRow = j;
                }
                //计算油，水，气日产均值
                for (int k = 0; k < 3; k++)
                {
                    if (productionDay[k].Equals(0))
                        averageData[k] = 0;
                    else
                        averageData[k] = sumData[k] / productionDay[k];
                }
                //填充数据
                FillOtherData(i, startRow, endRow, produceDay);
                FillProductionData(i, sumData, maxData, averageData);
                //为分类统计表记录数据
                for(int k=0; k<3; k++)
                {
                    allSum[k] += sumData[k];
                }
            }
        }
        /// <summary>
        /// 计算分类统计表中所需数据
        /// </summary>
        public static void RecordData()
        {     
            if (singleWellSumTable.Rows.Count == 0)
                SingleWellSum();
            //列顺序为生产天数、开井时率、累计产油、累计产水、累计产气、平均产油、平均产水、平均产气
            for (int col=10; col<18; col++)
            {
                List<double> templeData = new List<double>();
                for (int row=0; row<singleWellSumTable.Rows.Count; row++)
                {                    
                    double value = Convert.ToDouble(singleWellSumTable.Rows[row][col]);
                    templeData.Add(value);
                }
                singleWellData.AddRange(GetMaxMinAverageMedianData(templeData));
            }
            
        }
        #region 私有函数
        /// <summary>
        /// 初始化表格，根据模板表搭建
        /// </summary>
        private static void InitialTable()
        {
            string[] colName = { "起始行", "终止行", "投产时间","最后生产时间","时间跨度（天）","生产天数（天）","开井时率（%）",
                                 "累计产油（吨）","累计产水（方）","累计产气（万方）","平均日产油（吨/天）","平均日产水（方/天）","平均日产气（万方/天）",
                                 "最大日产油（吨/天）","最大日产水（方/天）","最大日产气（万方/天）"};
            singleWellSumTable = Ole.dataTables[0].Copy();
            singleWellSumTable.TableName = "3-单井汇总";
            //删除读进来的多余列（删除没有列名的列）
            for (int i = singleWellSumTable.Columns.Count - 1; i >= 0; i--)
            {
                if (singleWellSumTable.Columns[i].ColumnName.Contains("F"))
                    singleWellSumTable.Columns.Remove(singleWellSumTable.Columns[i].ColumnName);
            }
            //根据colName添加列名
            for (int i = 0; i < colName.Length; i++)
            {
                singleWellSumTable.Columns.Add(colName[i]);
            }
            //删除复制过来后没有数据的多余行（没有井名的删除）
            for (int i = singleWellSumTable.Rows.Count - 1; i >= 0; i--)
            {
                if (singleWellSumTable.Rows[i][2].Equals(DBNull.Value))
                    singleWellSumTable.Rows.RemoveAt(i);
                else break;
            }
        }
        /// <summary>
        /// 判断指向位置有无数据及是否与当前井号的相同
        /// </summary>
        /// <param name="wellNumString">当前处理井号</param>
        /// <param name="index">当前指向的数据表的行数</param>
        /// <returns></returns>
        private static bool NumCheck(string wellNumString, int index)
        {
            if (index >= Ole.dataTables[1].Rows.Count) return false;
            if (Ole.dataTables[1].Rows[index][2].ToString() == wellNumString)
                return true;
            else return false;
        }
        /// <summary>
        /// 考虑空单元格，对读入的数据作处理
        /// </summary>
        /// <param name="row">行号</param>
        /// <param name="col">列号</param>
        /// <returns></returns>
        private static double valueProcess(int row, int col)
        {
            double value;
            if (Ole.dataTables[1].Rows[row][col].Equals(DBNull.Value))
                value = 0;
            else
                value = Convert.ToDouble(Ole.dataTables[1].Rows[row][col]);
            return value;
        }
        /// <summary>
        /// double值的最大值函数
        /// </summary>
        private static double doubleMax(double x, double y)
        {
            if (x > y) return x;
            else return y;
        }
        /// <summary>
        /// 判断是否为实际生产日，若油，水，气三项日产量都为0，则不计入
        /// </summary>
        /// <param name="x">油，水，气日产量</param>
        /// <returns></returns>
        private static bool IsProduce(double[] x)
        {
            for (int i = 0; i < x.Length; i++)
            {
                if (!x[i].Equals(0))
                    return true;
            }
            return false;
        }
        /// <summary>
        /// 填充行数，日期，生产日等数据
        /// </summary>
        /// <param name="index">当前井号所在行数</param>
        /// <param name="startRow">开始行</param>
        /// <param name="endRow">结束行</param>
        /// <param name="produceDay">实际生产日</param>
        private static void FillOtherData(int index, int startRow, int endRow, int produceDay)
        {
            DateTime start = Convert.ToDateTime(Ole.dataTables[1].Rows[startRow][3]);
            DateTime end = Convert.ToDateTime(Ole.dataTables[1].Rows[endRow][3]);
            TimeSpan timeSpan = end.Subtract(start);
            double timeRate = (double)produceDay / timeSpan.Days * 100;
            singleWellSumTable.Rows[index][5] = startRow + 1;
            singleWellSumTable.Rows[index][6] = endRow + 1;
            singleWellSumTable.Rows[index][7] = start.ToShortDateString();
            singleWellSumTable.Rows[index][8] = end.ToShortDateString();
            singleWellSumTable.Rows[index][9] = timeSpan.Days;
            singleWellSumTable.Rows[index][10] = Math.Round((double)produceDay, 0);
            singleWellSumTable.Rows[index][11] = Math.Round(timeRate, 2);
        }
        /// <summary>
        /// 填充油，水，气各项数据
        /// </summary>
        /// <param name="index">当前井号行数</param>
        /// <param name="sumData">油水气累计总值</param>
        /// <param name="maxData">油水气最大值</param>
        /// <param name="averageData">油水气平均值</param>
        private static void FillProductionData(int index, double[] sumData, double[] maxData, double[] averageData)
        {
            for (int i = 0; i < 3; i++)
            {
                singleWellSumTable.Rows[index][12 + i] = Math.Round(sumData[i], 4);
                singleWellSumTable.Rows[index][15 + i] = Math.Round(averageData[i], 4);
                singleWellSumTable.Rows[index][18 + i] = Math.Round(maxData[i], 4);
            }
        }
        /// <summary>
        /// 求解一个double数组的最大值、最小值、平均值以及中位数
        /// </summary>
        /// <param name="data">double数据</param>
        /// <returns></returns>
        private static List<double> GetMaxMinAverageMedianData(List<double> data)
        {
            List<double> result = new List<double>();
            data.Sort();
            result.Add(data[data.Count - 1]);
            result.Add(data[0]);
            result.Add(data.Sum() / data.Count);
            double median;
            if (data.Count % 2 == 0)
                median = (data[data.Count / 2] + data[data.Count / 2 - 1]) / 2;
            else
                median = data[data.Count / 2];
            result.Add(median);
            return result;
        }
        #endregion
    }
}
